import random
import re
import time
from functools import wraps

import pymysql
from selenium import webdriver
import os
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions
import validators

import base_settings
from Database.init import init
from Spiders.Instagram import settings
from Browser.Cookies.DriverCookie import DriverCookie
from SMTP.SmtpServer import SmtpServer


class Spider():
    driver = None
    mysql = None
    operator = None
    page = 1

    def __init__(self):
        # ----启动浏览器----
        if self.driver is None:
            # 1 浏览器配置
            option = webdriver.ChromeOptions()
            option.add_argument('--profile-directory=Default')
            option.add_argument(r"user-data-dir=" + settings.SPIDER_DRIVER_DATA_DIR + 'Instagram\Google')  # 浏览器数据路径
            # option.add_argument("blink-settings=imagesEnabled=false")  # 不加载图片
            option.add_argument("--start-maximized")  # 开始最大化
            option.add_argument("--test-type")
            option.add_argument("--ignore-certificate-errors")  # 忽略证书错误

            option.add_argument("--disable-popup-blocking")  # 禁用弹出拦截
            option.add_argument("no-sandbox")  # 取消沙盒模式
            option.add_argument("no-default-browser-check")  # 禁止默认浏览器检查
            option.add_argument("about:histograms")
            option.add_argument("about:cache")

            option.add_argument("disable-extensions")  # 禁用扩展
            option.add_argument("disable-glsl-translator")  # 禁用GLSL翻译

            option.add_argument("disable-translate")  # 禁用翻译
            option.add_argument("--disable-gpu")  # 谷歌文档提到需要加上这个属性来规避bug
            option.add_argument("--disable-dev-shm-usage")
            option.add_argument("--hide-scrollbars")  # 隐藏滚动条, 应对一些特殊页面

            # 2 查找驱动并驱动浏览器
            driver_path = base_settings.PB + '/Browser/Drivers/chromedriver_win32/chromedriver.exe'
            print(driver_path)
            driver = webdriver.Chrome(executable_path=driver_path, options=option)
            self.driver = driver

        # ----初始化数据库----
        if self.mysql is None:
            self.mysql = init()

    def check_login(func):
        """
        检测登录
        :return:
        """

        @wraps(func)
        def with_login(*args, **kwargs):
            """

            :type driver: WebDriver
            """
            print(func.__name__ + " was called")
            driver = args[1]
            login_url = 'https://www.instagram.com/accounts/login/'

            # 登录回调:需要登录时登录
            def login_callback():
                # 查询是否有登陆框，没有则等待，直到有，最多等待10S
                WebDriverWait(driver, 10).until(
                    expected_conditions.presence_of_element_located(
                        (By.XPATH, '//*[@id="loginForm"]/div/div[1]/div/label/input'))
                )
                driver.find_element_by_xpath('//*[@id="loginForm"]/div/div[1]/div/label/input').send_keys(
                    settings.INS_ACCOUNT)
                driver.find_element_by_xpath('//*[@id="loginForm"]/div/div[2]/div/label/input').send_keys(
                    settings.INS_PASSWORD)
                print('提交登录...')
                driver.find_element_by_xpath('//*[@id="loginForm"]/div/div[3]/button').click()

            # driver_cookie = DriverCookie().read_cookies(login_url, self.driver, login_callback)
            # print('检查登录Cookies状态：')
            # print(driver_cookie)
            # 是登录域名时 获取驱动cookie,避免多次登录:检测是否是登录地址，以及是否有cookies
            if driver.current_url.find(settings.INS_DOMAIN) and driver.current_url.find(login_url):
                try:
                    # 进入登录
                    driver_cookie = DriverCookie().read_cookies(login_url, driver, login_callback)
                    print('登录完成')
                    print(driver_cookie)
                except Exception:
                    print('无需登录')
            else:
                print('已登录...')
            return func(*args, **kwargs)

        return with_login

    def google_search(self):
        """
        google搜索
        :return:
        """
        print('google搜索...')
        search = 'site:' + settings.SPIDER_SEARCH_SITE + ' ' + settings.SPIDER_SEARCH_WORDS
        self.driver.execute_script('window.open("https://www.google.com","_blank");')  # 新开标签页
        self.driver.switch_to.window(self.driver.window_handles[1])

        google_input = WebDriverWait(self.driver, 5).until(
            expected_conditions.presence_of_element_located(
                (By.XPATH, '/html/body/div[1]/div[3]/form/div[1]/div[1]/div[1]/div/div[2]/input')
            )
        )
        print('查询：' + search)
        google_input.send_keys(search)
        google_input.send_keys(Keys.ENTER)

        # 读取查询的列表
        links = self.driver.find_elements_by_xpath(
            '/html/body/div[7]/div/div[9]/div[1]/div/div[2]/div[2]/div/div/div/div')
        print('第1页')
        for i, link in enumerate(links):
            link = link.find_element_by_xpath('//*[@id="rso"]/div/div[' + str(i + 1) + ']/div/div[1]/a')
            href = link.get_attribute("href")
            self.hit_link(self.driver, href)

        # 返回google搜索窗口
        self.driver.switch_to.window(self.driver.window_handles[-1])

        # 进入下一页
        self.next()

    @check_login
    def hit_link(self, driver, href: str):
        """
        点击链接
        :param driver:
        :param href:
        :return:
        """
        # 检查连接是否被爬取过
        cursor = self.mysql.cursor()
        cursor.execute('select * from `crawled` where `url`="' + href + '"')
        has_url = cursor.fetchone()
        cursor.close()
        if has_url is None:
            # 添加已爬取的url
            cursor = self.mysql.cursor()
            cursor.execute('insert into `crawled` (`url`) values("' + href + '")')
            self.mysql.commit()
            cursor.close()
            # 新开标签页
            driver.execute_script('window.open("' + href + '","_blank");')
            driver.switch_to.window(driver.window_handles[-1])

            self.check_email_and_send()

            driver.close()
            # 目标页模拟人工
            time.sleep(random.randint(1, settings.SPIDER_RAND_TARGET_RESIDENCE_MAX_TIME_PER_PAGE))
            # 返回google搜索窗口
            driver.switch_to.window(driver.window_handles[-1])
        else:
            print('url已经爬取过：' + href)

    # 读取下一页
    def next(self):
        self.page += 1
        print('进入下一页:' + str(self.page))
        time.sleep(3)
        # 点击下一页
        self.driver.find_element_by_xpath(
            '/html/body/div[7]/div/div[9]/div[1]/div/div[6]/span[1]/table/tbody/tr/td[12]/a').click()
        # 等待加载读取查询的列表
        next_page = WebDriverWait(self.driver,
                                  random.randint(5, settings.SPIDER_GOOGLE_SEARCH_RAND_WAITE_MAX_TIME_PER_PAGE)).until(
            expected_conditions.presence_of_element_located(
                (By.XPATH, '/html/body/div[7]/div/div[9]/div[1]/div/div[2]/div[2]/div/div/div/div[1]/div/div')
            )
        )
        links = self.driver.find_elements_by_xpath(
            '/html/body/div[7]/div/div[9]/div[1]/div/div[2]/div[2]/div/div/div/div[1]/div/div')
        for i, link in enumerate(links):
            link = link.find_element_by_xpath('//*[@id="rso"]/div/div[' + str(i + 1) + ']/div/div[1]/a')
            href = link.get_attribute("href")
            self.hit_link(self.driver, href)
        self.next()

    # 检测邮件并发送
    def check_email_and_send(self):
        # 查找邮箱是否存在
        try:
            profile_info = WebDriverWait(self.driver, 10).until(
                expected_conditions.presence_of_element_located(
                    (By.XPATH, '/html/body/div[1]/section/main/div/header/section/div[2]/span')
                )
            )
            # 提取邮件地址
            words = re.findall(
                r'([a-zA-Z0-9_.+-]+@[a-pr-zA-PRZ0-9-]+\.[a-zA-Z0-9-.]+)', profile_info.text)
            print('找到账号的邮件数据')
            print(words)
            # 粉丝筛选
            print('粉丝筛选：' + str(settings.FANS_MIN_NUMBER) + '-' + str(settings.FANS_MAX_NUMBER))
            fans = self.driver.find_element_by_xpath(
                '/html/body/div[1]/section/main/div/header/section/ul/li[2]/a/span').get_attribute('title')
            receiver_nickname = self.driver.find_element_by_xpath(
                '/html/body/div[1]/section/main/div/header/section/div[1]/h2').text
            print('粉丝：' + fans)
            if settings.FANS_MIN_NUMBER < int(fans.replace(',', '')) < settings.FANS_MAX_NUMBER:
                print('粉丝合格：' + fans)
                for email in words:
                    if validators.email(email):
                        # 检测邮箱
                        cursor = self.mysql.cursor()
                        cursor.execute('select * from `celebrity` where email="' + email + '"')
                        has_email = cursor.fetchone()
                        cursor.close()
                        self.mysql.commit()
                        if has_email is None:
                            print('正在发送邮件...')
                            smtp: SmtpServer = SmtpServer()
                            # sent_result = True
                            sent_result = smtp.send_mail(settings.EMAIL_SUBJECT, settings.EMAIL_SENT_CONTENT, email,
                                                         receiver_nickname)
                            if sent_result:
                                print('发送成功！对方邮件：' + email)
                                print('数据库录入...')
                                sql = '''
                                INSERT INTO `celebrity` (`source_url`,`operator_id`,`source`,`nickname`,`email`,`fans`) 
                                VALUES('{source_url}','{operator_id}','{source}','{nickname}','{email}','{fans}')
                                '''
                                sql = sql.format(source_url=self.driver.current_url, operator_id=self.operator[0],
                                                 source='ins', nickname=receiver_nickname,
                                                 email=email,
                                                 fans=int(fans.replace(',', '')))
                                print(sql)
                                cursor = self.mysql.cursor()
                                cursor.execute(sql)
                                self.mysql.commit()
                                cursor.close()
                                print('成功数据库录入...')
                            else:
                                print('发送失败！对方邮件：' + email)
                        else:
                            print('邮箱已经发送过：' + email)
                    else:
                        print('邮箱验证不通过：' + email)
            else:
                print('粉丝不在筛选范围：' + fans)
        except Exception:
            print('查不到信息：有可能是私密账户...返回继续查下一个连接')

        time.sleep(random.randint(1, settings.SPIDER_RAND_TARGET_RESIDENCE_MAX_TIME_PER_PAGE))


if (__name__ == '__main__'):
    # FIXME 多线程未开发
    main = Spider()
    main.check_login()
    main.google_search()
